#coding:utf-8

import pickle
from twisted.internet import reactor, defer
from twisted.internet.protocol import Protocol, Factory, ClientFactory
import time
import base
import report
import testcase
from core import stock
import re


dataflag = "<--%s-->"
datafilter = re.compile(r'(?<=\<--).*?(?=--\>)')
    
class UserServerProtocol(Protocol):
    def __init__(self, player):
        self.player = player
        self.router = {"action": self.parseAction,
                       "testcase": self.parseTestCase,
                       "islogin": self.parseLoginState,
                       "istesting": self.parseTestState,
                       }
        
    def connectionMade(self):
        self.factory.plist.append(self)
        #self.player.requestAllVehicleState()
        
    def connectionLost(self, reason):
        self.factory.plist.remove(self)

    def dataReceived(self, data):
        for d in datafilter.findall(data):
            d = stock.loads(d)
            tel = d.get('tel', '00000000')
            for key in d:
                callable = self.router.get(key)
                if callable:
                    callable(tel, d[key])
      
    def write(self, msg):
        msg = stock.dumps(msg)
        self.transport.write(dataflag%msg)
        
    def parseTestCase(self, tel, tests):
        vehicle = self.player.getVehicle(tel)
        if not vehicle:
            vehicle = self.player.createVehicle(tel)
        for test in tests:
            data = test.get("data")
            repeat = test.get("repeat")
            patience = test.get("patience")
            rest = test.get("rest")
            case = testcase.TestCase(data, repeat, patience, rest)
            vehicle.appendTestCase(case)
        
    def parseAction(self, tel, data):
        todo = data.get("todo")
        if todo == "start":
            self.parseTestCase(tel, data.get("testcase"))
            reportName = data.get("report", "")
            vehicle = self.player.getVehicle(tel)
            if not vehicle:
                vehicle = self.player.createVehicle(tel)
            vehicle.setReportPath(reportName)
            vehicle.startTest()
        elif todo == "stop":
            vehilce = self.player.getVehicle(tel)
            if vehilce:
                vehicle.stopTest()
                
    def parseLoginState(self, tel, data):
        vehilce = self.player.getVehicle(tel)
        self.factory.sendLoginState(tel, bool(vehilce))
    
    def parseTestState(self, tel, data):
        pass
        
class UserServer(Factory):
    def __init__(self, player):
        self.player = player
        player.user = self
        self.plist = []
        
    def createDataDocument(self, tel):
        return {"tel": tel}
        
    def buildProtocol(self, address):
        p = UserServerProtocol(self.player)
        p.factory = self
        return p
    
    def write(self, data):
        for p in self.plist:
            p.write(data)
    
    def sendMessage(self, tel, msg):
        doc = self.createDataDocument(tel)
        doc.update({"message": msg})
        self.write(doc)
    
    def sendData(self, tel, data):
        doc = self.createDataDocument(tel)
        doc.update({"data": data})
        self.write(doc)
            
    def sendLoginState(self, tel, state):
        doc = self.createDataDocument(tel)
        doc.update({"login": state})
        self.write(doc)
            
    def sendTestProcess(self, tel, testTime, totalTime):
        pass
            
    def sendTestStart(self, tel):
        pass
            
    def sendTestStop(self, tel):
        pass
            
    def sendTestPause(self, tel):
        pass

# ------------------------------------------

class UserClientProtocol(Protocol):
    def __init__(self, ctrl):
        self.report = ctrl.report_panel
        self.vehicle = ctrl.vehicle_panel
        self.status = ctrl.status_panel
        self.router = {"message": self.parseMessage,
                       "data": self.parseData,
                       "login": self.parseLoginState,
                       "process": self.parseTestProcess,
                       }
        
    def connectionMade(self):
        if self.report:
            self.report.writeMessage("0000000", u"服务器已连接")
            self.status.showConnection(True)
            
    def connectionLost(self, reason):
        if self.report:
            self.report.writeMessage("0000000", u"服务器连接丢失")
            self.status.showConnection(False)
    
    def dataReceived(self, data):
        for d in datafilter.findall(data):
            d = stock.loads(d)
            tel = d.get("tel")
            for key in d:
                callable = self.router.get(key)
                if callable:
                    callable(tel, d[key])
        
    def parseMessage(self, tel, msg):
        self.report.writeMessage(tel, msg)
    
    def parseData(self, tel, data):
        self.report.writeData(tel, data)
        
    def parseLoginState(self, tel, state):
        self.vehicle.updateVehicleState(tel, state)
        
    def parseTestProcess(self, tel, process):
        pass
        
    def loseConnection(self):
        self.transport.loseConnection()
    
    def write(self, msg):
        # python2.5 socket只能发送string类型不能发送unicode类型.
        # twisted底部tcp的socket遇到非string类型时, 不会将其转换成string再发送
        # twisted的socket似乎默认为不处理非string类型的数据.
        print msg
        assert isinstance(msg, str), "Msg is only sended as string type. \
            msg:%s type(%s)"%(msg, type(msg))
        self.transport.write(msg)
        
class InfoControlMixin:
    def writeData(self, data):
        if self.onlyProtocol:
            msg = stock.dumps(data)
            self.onlyProtocol.transport.write(dataflag%msg)
    
    def createDataDocment(self, tel):
        return {"tel" : tel}
            
    def requestStartTest(self, tel, reportPath, testList):
        doc = self.createDataDocment(tel)
        action = {"todo": "start", "report": reportPath}
        tests = []
        for case in testList:
            tests.append( {"data": case.getData(),
                           "repeat": case.getRepeat(),
                           "patience": case.getPatience(),
                           "rest": case.getRest(),})
        action.update({"testcase": tests})
        doc.update({"action" : action})
        self.writeData(doc)
            
    def requestStopTest(self, tel):
        doc = self.createDataDocment(tel)
        action = {"todo": "stop"}
        doc.update({"action" : action})
        self.writeData(doc)
             
    def requestLoginState(self, tel):
        doc = self.createDataDocment(tel)
        doc.update({"islogin" : 1})
        self.writeData(doc)
            
    def requestTestState(self, tel):
        doc = self.createDataDocment(tel)
        doc.update({"istesting" : 1})
        self.writeData(doc)
        
class UserConnector(ClientFactory, InfoControlMixin):
    delay = 10.0
    onlyProtocol = None
    def __init__(self, control):
        self.ctrl = control
        
    def buildProtocol(self, address):
        self.onlyProtocol = UserClientProtocol(self.ctrl)
        return self.onlyProtocol
        
    def updateConnect(self, host, port):
        self.stopConnect()
        self.connect(host, port)
        
    def stopConnect(self):
        if self.onlyProtocol:
            self.onlyProtocol.loseConnection()
        
    def connect(self, host, port):
        self.host, self.port = host, port
        reactor.connectTCP(host, port, self)
    
    def startedConnecting(self, connector):
        if self.host != connector.host or self.port != connector.port:
            connector.stopConnecting()
        
    def clientConnectionLost(self, connector, reason):
        self.onlyProtocol = None
        self.retry(connector)
        
    def clientConnectionFailed(self, connector, reason):
        self.onlyProtocol = None
        self.retry(connector)

    def retry(self, connector):
        if self.host != connector.host or self.port != connector.port:
            return
        reactor.callLater(self.delay, connector.connect)
        
    def isConnected(self):
        if self.onlyProtocol:
            return True
        else:
            return False
